package NG::Sys::Form;
use strict;
use warnings;
use utf8;

use NG::Sys::App;

sub new {
	my ($class,$app,$cgi) = @_;
	my $self = bless {
		data => {},
		input => {},
		cgi => $cgi,
		ip => $ENV{HTTP_X_REAL_IP},
	}, $class;

	my $input = $self->{input};
	my $data = $self->{data};
	$data->{rand} = rand();

	if($cgi){
		for my $name ($cgi->param){
			my @value = $cgi->param($name);
			my $value = @value ? (@value == 1 ? $value[0] : \@value) : undef;
			if(ref($value) ne 'Fh'){
				if(ref $value){
					utf8::decode($_) for @$value;
				}else{
					utf8::decode($value);
				}
				my @tree = split /\./, $name;
				my $node = $input;
				while (my $leap = shift @tree ) {
					$node->{$leap} ||= @tree ? {}:$value;
					$node = $node->{$leap};
				}
			}else{
				my( $parent, $field ) = split /\./, $name;
				my ($uploadInfo) = $cgi->uploadInfo($value);
				my $info = {
					content => sub {
							local $/;
							<$value>;
						},
					type => $uploadInfo->{'Content-Type'},
					};
				$info->{filename}  = ( $uploadInfo->{'Content-Disposition'} =~ /filename=".*[\\\/]([^"]*)"/);
				if($field){
					$input->{$parent}{$field} = $info;
				}else{
					$input->{$name} = $info;
				}
			}
		}
	}
	return $self;
}
sub set_error {
	my($self,$code,$text) = @_;
	$self->{data}{error} = $code;
	$self->{data}{text} = $text;
	return $self;
}
sub set_data {
	my $self = shift;
	my $args;
	if($@ && ref $_[0]){
		$args = $_[0];
	}else{
		$args = {@_};
	}
	while(my($k,$v) = each %$args){
		$self->{data}{$k} = $v;
	}
	return $self;
}
sub cookie {
	my($self,$name) = @_;
	return $self->{cgi}->cookie($name);
}

sub set_header {
	my ($self,$key,$value) = @_;
	($self->{header_to_sent} ||= {})->{$key} = $value;
}

sub push_header {
	my ($self,$key,$value) = @_;
	push @{($self->{header_to_sent} ||= {})->{$key} ||= []},$value;
}

#-name=>'sessionID',
#-value=>'xyzzy',
#-expires=>'+1h',
#-path=>'/cgi-bin/database',
#-domain=>'.capricorn.org',
#-secure=>1
sub add_cookie {
	my ($self,@cookie) = @_;
	if(@cookie and ref $cookie[0]){
		@cookie = %{$cookie[0]};
	}
	my $cs = $self->{cgi}->cookie(@cookie);
	push_header($self,'-cookie', $cs);
}

sub raw_header {
	my ($self) = @_;
	$self->{header_to_sent} ||= {};

	if(($self->{header_to_sent}{-type} ||= "text/html") =~ /text/){
		$self->{header_to_sent}{-charset} ||= "utf-8";
	}
	return delete $self->{header_to_sent};
}

sub header {
	my ($self) = @_;
	unless($self->{header_sent}){
		$self->{header_sent} = 1;
		my $r = $self->{cgi}->header(%{raw_header($self)});
		return $r;
	}else{
		die "header already sent\n";
	}
}
sub output {
	my ($self,$content) = @_;
	if(utf8::is_utf8($content)){
		utf8::encode($content);
	}
	my $length = length $content;
	set_header($self,-Content_length => $length);
	print header($self),$content;
}
sub process {
	my ($self,$template) = @_;
	if(ref $template && UNIVERSAL::can($template,"process")){
		my $str = $template->process($self->{data});
		output($self,$str);
	}else{
		die "cannot call process on '$template'";
	}
}
sub process_as_json {
	my ($self) = @_;
	require JSON::XS;
	my $str = JSON::XS::encode_json($self->{data});
	set_header($self,'-type'=>"text/json");
	output($self,$str);
}
sub redirect {
	my ($self,$url) = @_;
	$self->{header_sent} = 1;
	print $self->{cgi}->redirect(-Location=>$url,%{raw_header($self)});
}
1;
